S01-13 JavaSE-枚举和注解
[TOC]
需求场景
创建季节(Season)对象,要求:
- 季节对象固定(春、夏、秋、冬)
- 只读,不能修改
问题分析
- 季节值是有限的4个
- 需要只读属性,不能修改
- 传统类设计无法保证对象唯一性
解决方案-枚举
- 枚举(enumeration,简写enum)是一组常量的集合
- 枚举属于特殊类,仅包含有限的特定对象
枚举的两种实现方式
- 自定义类实现枚举
- 使用enum关键字实现枚举
自定义类实现枚举-应用案例
java
package com.hspedu.enum_;
/**
* 自定义枚举类实现
*/
public class Enumeration02 {
public static void main(String[] args) {
System.out.println(Season.AUTUMN);
System.out.println(Season.SPRING);
}
}
class Season { // 枚举类
private String name;
private String desc; // 描述
// 1. 私有构造器,防止直接new
private Season(String name, String desc) {
this.name = name;
this.desc = desc;
}
// 2. 本类内部创建固定对象
public static final Season SPRING = new Season("春天", "温暖");
public static final Season SUMMER = new Season("夏天", "炎热");
public static final Season AUTUMN = new Season("秋天", "凉爽");
public static final Season WINTER = new Season("冬天", "寒冷");
// 3. 提供get方法,无set方法(只读)
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}自定义类实现枚举-小结
- 构造器私有化
- 本类内部创建固定对象
- 对外暴露对象(public final static修饰)
- 提供get方法,不提供set方法
enum关键字实现枚举-快速入门
java
package com.hspedu.enum_;
/**
* 使用enum关键字实现枚举
*/
public class Enumeration03 {
public static void main(String[] args) {
System.out.println(Season2.AUTUMN);
System.out.println(Season2.SUMMER);
}
}
// 枚举类
enum Season2 {
// 枚举对象(必须放在行首),多个用逗号分隔,末尾可加封号
SPRING("春天", "温暖"),
SUMMER("夏天", "炎热"),
AUTUMN("秋天", "凉爽"),
WINTER("冬天", "寒冷");
private String name;
private String desc;
// 构造器(私有,默认可以省略private)
Season2(String name, String desc) {
this.name = name;
this.desc = desc;
}
// 无参构造器(如果需要)
private Season2() {}
// get方法
public String getName() {
return name;
}
public String getDesc() {
return desc;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
'}';
}
}enum关键字实现枚举注意事项
- enum类默认继承Enum类,且是final类(不能被继承)
- 传统
public static final Season SPRING = new Season(...)简化为SPRING(...) - 无参构造器创建枚举对象时,可省略
() - 多个枚举对象用逗号分隔,末尾加分号
- 枚举对象必须放在枚举类行首
enum关键字实现枚举-课堂练习
练习1
java
// 代码是否正确? 含义是什么?
enum Gender{
BOY, GIRL; // 调用无参构造器
}- 语法正确
- 枚举类Gender,无属性
- 两个枚举对象BOY、GIRL(无参构造器创建)
练习2
java
enum Gender2{
BOY,GIRL;
}
public class Test {
public static void main(String[] args) {
Gender2 boy = Gender2.BOY;
System.out.println(boy); // 输出BOY(调用父类Enum的toString())
Gender2 boy2 = Gender2.BOY;
System.out.println(boy2 == boy); // True(同一对象)
}
}enum常用方法说明
enum类隐式继承Enum类,可使用以下常用方法:
| 方法名 | 详细描述 |
|---|---|
| valueOf | 传递枚举类型Class和常量名,返回匹配的枚举常量 |
| toString | 返回当前枚举常量名称(可重写) |
| equals | 直接使用==比较,用于集合中 |
| hashCode | 与equals保持一致,不可变 |
| getDeclaringClass | 获取枚举常量所属的枚举类Class对象 |
| name | 返回枚举常量名称(不可重写) |
| ordinal | 返回枚举常量的次序(从0开始) |
| compareTo | 比较两个枚举常量的次序(编号差值) |
| clone | 不可克隆,抛出CloneNotSupportedException |
方法应用实例(EnumMethod.java)
java
package com.hspedu.enum_;
/**
* 演示Enum类常用方法
*/
public class EnumMethod {
public static void main(String[] args) {
Season2 autumn = Season2.AUTUMN;
// 1. name():返回枚举对象名称
System.out.println(autumn.name()); // AUTUMN
// 2. ordinal():返回次序(从0开始)
System.out.println(autumn.ordinal()); // 2
// 3. values():返回所有枚举对象数组
Season2[] values = Season2.values();
System.out.println("===遍历枚举对象===");
for (Season2 season : values) {
System.out.println(season);
}
// 4. valueOf():将字符串转为枚举对象
Season2 autumn1 = Season2.valueOf("AUTUMN");
System.out.println("autumn1=" + autumn1);
System.out.println(autumn == autumn1); // True
// 5. compareTo():比较次序差值
System.out.println(Season2.AUTUMN.compareTo(Season2.SUMMER)); // 2-3=-1
}
}enum常用方法课堂练习
需求
声明Week枚举类,包含星期一至星期日,使用values()遍历输出。
代码实现
java
package com.hspedu.enum_;
public class EnumExercise02 {
public static void main(String[] args) {
// 获取所有枚举对象
Week[] weeks = Week.values();
System.out.println("===所有星期的信息如下===");
for (Week week : weeks) {
System.out.println(week);
}
}
}
enum Week {
MONDAY("星期一"),
TUESDAY("星期二"),
WEDNESDAY("星期三"),
THURSDAY("星期四"),
FRIDAY("星期五"),
SATURDAY("星期六"),
SUNDAY("星期日");
private String name;
// 构造器
private Week(String name) {
this.name = name;
}
// 重写toString()
@Override
public String toString() {
return name;
}
}enum实现接口
- enum类不能继承其他类(已隐式继承Enum)
- 枚举类可以实现接口,与普通类实现接口语法一致
代码示例
java
package com.hspedu.enum_;
public class EnumDetail {
public static void main(String[] args) {
Music.CLASSICMUSIC.playing();
}
}
// 接口
interface IPlaying {
void playing();
}
// 枚举类实现接口
enum Music implements IPlaying {
CLASSICMUSIC;
@Override
public void playing() {
System.out.println("播放好听的音乐...");
}
}注解的理解
- 注解(Annotation)又称元数据,用于修饰解释程序元素(包、类、方法等)
- 不影响程序逻辑,但可被编译或运行
- JavaSE中用途:标记过时功能、忽略警告等
- JavaEE中用途:配置应用、替代XML配置等
基本的Annotation介绍
使用Annotation时需加@符号,作为修饰符使用。
三个基本Annotation
@Override:限定方法重写父类方法,仅用于方法@Deprecated:标记程序元素已过时@SuppressWarnings:抑制编译器警告
基本的Annotation应用案例
@Override注解(Override_.java)
java
package com.hspedu.annotation_;
public class Override_ {
public static void main(String[] args) {
}
}
class Father { // 父类
public void fly() {
System.out.println("Father fly...");
}
public void say() {}
}
class Son extends Father { // 子类
// @Override 表示重写父类方法
@Override
public void fly() {
System.out.println("Son fly....");
}
@Override
public void say() {}
}注意事项:
- 编译器会检查是否真的重写了父类方法
- 仅能修饰方法
- 源码:
@Target(ElementType.METHOD)
@Deprecated注解(Deprecated_.java)
java
package com.hspedu.annotation_;
public class Deprecated_ {
public static void main(String[] args) {
A a = new A();
a.hi(); // 警告:方法已过时
System.out.println(a.n1); // 警告:字段已过时
}
}
@Deprecated // 类已过时
class A {
@Deprecated // 字段已过时
public int n1 = 10;
@Deprecated // 方法已过时
public void hi() {}
}注意事项:
- 可修饰类、方法、字段、包、参数等
- 用于版本升级过渡
- 源码:
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
@SuppressWarnings注解(SuppressWarnings_.java)
java
package com.hspedu.annotation_;
import java.util.ArrayList;
import java.util.List;
// 抑制多种警告
@SuppressWarnings({"rawtypes", "unchecked", "unused"})
public class SuppressWarnings_ {
public static void main(String[] args) {
List list = new ArrayList();
list.add("jack");
list.add("tom");
int i; // 未使用但无警告
System.out.println(list.get(1));
}
public void f1() {
@SuppressWarnings({"rawtypes"})
List list = new ArrayList();
list.add("jack");
}
}常用抑制类型:
all:抑制所有警告rawtypes:抑制未指定泛型的警告unchecked:抑制未检查的警告unused:抑制未使用变量的警告
JDK的元Annotation(了解)
元Annotation用于修饰其他Annotation,共4种:
| 元注解 | 作用 |
|---|---|
| Retention | 指定注解的作用范围(SOURCE/CLASS/RUNTIME) |
| Target | 指定注解可修饰的程序元素 |
| Documented | 指定注解是否在javadoc中体现 |
| Inherited | 子类继承父类的注解 |
@Retention
RetentionPolicy.SOURCE:编译器使用后丢弃(如@Override)RetentionPolicy.CLASS:记录在class文件中,JVM不保留(默认)RetentionPolicy.RUNTIME:记录在class文件中,JVM保留,可通过反射获取
@Target
指定注解可修饰的程序元素(如METHOD、TYPE、FIELD等)
第10章作业
代码执行结果题(Homework01.java)
java
class Car {
static String color = "white";
double price = 10;
public Car() {
this.price = 9;
this.color = "red";
}
public Car(double price) {
this.price = price;
}
public String toString() {
return price + "\t" + color;
}
}
public class Homework01 {
public static void main(String[] args) {
Car c1 = new Car(100);
System.out.println(c1); // 100.0 red
Car c = new Car();
System.out.println(c); // 9.0 red
}
}编程题(Homework02.java)- 衣服序列号生成
java
package com.hspedu.homework;
public class Homework02 {
public static void main(String[] args) {
// 测试getNextNum方法
System.out.println(Frock.getNextNum()); // 100100
System.out.println(Frock.getNextNum()); // 100200
// 测试三个Frock对象
Frock f1 = new Frock();
Frock f2 = new Frock();
Frock f3 = new Frock();
System.out.println(f1.getSerialNumber()); // 100300
System.out.println(f2.getSerialNumber()); // 100400
System.out.println(f3.getSerialNumber()); // 100500
}
}
class Frock {
// 私有静态属性:序列号起始值
private static int currentNum = 100000;
// 序列号属性
private int serialNumber;
// 构造器:获取唯一序列号
public Frock() {
this.serialNumber = getNextNum();
}
// 静态方法:生成下一个序列号
public static int getNextNum() {
currentNum += 100;
return currentNum;
}
// get方法
public int getSerialNumber() {
return serialNumber;
}
}编程题(Homework03.java)- 抽象类使用
java
package com.hspedu.homework;
public class Homework03 {
public static void main(String[] args) {
Animal cat = new Cat();
cat.shout(); // 猫会喵喵叫
Animal dog = new Dog();
dog.shout(); // 狗会汪汪叫
}
}
// 抽象动物类
abstract class Animal {
public abstract void shout();
}
// 猫类
class Cat extends Animal {
@Override
public void shout() {
System.out.println("猫会喵喵叫");
}
}
// 狗类
class Dog extends Animal {
@Override
public void shout() {
System.out.println("狗会汪汪叫");
}
}编程题(Homework04.java)- 匿名内部类使用
java
package com.hspedu.homework;
public class Homework04 {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
// 测试计算功能:10+20
cellphone.testWork(new Calculator() {
@Override
public double work(double n1, double n2) {
return n1 + n2;
}
}, 10, 20);
// 测试计算功能:50-30
cellphone.testWork(new Calculator() {
@Override
public double work(double n1, double n2) {
return n1 - n2;
}
}, 50, 30);
}
}
// 计算器接口
interface Calculator {
double work(double n1, double n2);
}
// 手机类
class Cellphone {
// 测试计算功能
public void testWork(Calculator calculator, double n1, double n2) {
double result = calculator.work(n1, n2);
System.out.println("计算结果:" + result);
}
}编程题(Homework05.java)- 局部内部类
java
package com.hspedu.homework;
public class Homework05 {
public static void main(String[] args) {
A a = new A();
a.m1();
}
}
class A {
private String name = "外部类A的name";
public void m1() {
// 局部内部类B
class B {
private final String name = "局部内部类B的name";
public void show() {
// 打印内部类和外部类的name
System.out.println("内部类name:" + name);
System.out.println("外部类name:" + A.this.name);
}
}
// 创建B对象并调用方法
B b = new B();
b.show();
}
}编程题(Homework06.java)- 工厂模式+接口
java
package com.hspedu.homework;
public class Homework06 {
public static void main(String[] args) {
// 实例化唐僧
Person tangseng = new Person("唐僧", VehicleFactory.getHorse());
tangseng.useVehicle(); // 使用马匹
// 遇到大河,切换交通工具
tangseng.setVehicles(VehicleFactory.getBoat());
tangseng.useVehicle(); // 使用船只
}
}
// 交通工具接口
interface Vehicles {
void work();
}
// 马匹类
class Horse implements Vehicles {
@Override
public void work() {
System.out.println("马匹奔跑...");
}
}
// 船只类
class Boat implements Vehicles {
@Override
public void work() {
System.out.println("船只航行...");
}
}
// 交通工具工厂类
class VehicleFactory {
// 获取马匹
public static Vehicles getHorse() {
return new Horse();
}
// 获取船只
public static Vehicles getBoat() {
return new Boat();
}
}
// 人类
class Person {
private String name;
private Vehicles vehicles;
// 构造器
public Person(String name, Vehicles vehicles) {
this.name = name;
this.vehicles = vehicles;
}
// 使用交通工具
public void useVehicle() {
System.out.println(name + "使用");
vehicles.work();
}
// setter方法
public void setVehicles(Vehicles vehicles) {
this.vehicles = vehicles;
}
}编程题(Homework07.java)- 成员内部类
java
package com.hspedu.homework;
public class Homework07 {
public static void main(String[] args) {
// 测试不同温度
Car car1 = new Car(50);
car1.getAir().flow(); // 吹冷气
Car car2 = new Car(-5);
car2.getAir().flow(); // 吹暖气
Car car3 = new Car(25);
car3.getAir().flow(); // 关闭空调
}
}
class Car {
private double temperature; // 温度
// 成员内部类:空调
class Air {
public void flow() {
if (temperature > 40) {
System.out.println("温度超过40度,吹冷气");
} else if (temperature < 0) {
System.out.println("温度低于0度,吹暖气");
} else {
System.out.println("温度适宜,关闭空调");
}
}
}
// 构造器
public Car(double temperature) {
this.temperature = temperature;
}
// 获取空调对象
public Air getAir() {
return new Air();
}
}编程题(Homework08.java)- 枚举类
java
package com.hspedu.homework;
public class Homework08 {
public static void main(String[] args) {
// 测试show方法
for (Color color : Color.values()) {
color.show();
}
// switch中使用枚举
Color color = Color.RED;
switch (color) {
case RED:
System.out.println("选中红色");
break;
case BLUE:
System.out.println("选中蓝色");
break;
case BLACK:
System.out.println("选中黑色");
break;
case YELLOW:
System.out.println("选中黄色");
break;
case GREEN:
System.out.println("选中绿色");
break;
}
}
}
// 接口
interface ShowColor {
void show();
}
// 颜色枚举类
enum Color implements ShowColor {
// 枚举对象及属性值
RED(255, 0, 0),
BLUE(0, 0, 255),
BLACK(0, 0, 0),
YELLOW(255, 255, 0),
GREEN(0, 255, 0);
// 属性
private int redValue;
private int greenValue;
private int blueValue;
// 构造器
Color(int redValue, int greenValue, int blueValue) {
this.redValue = redValue;
this.greenValue = greenValue;
this.blueValue = blueValue;
}
// 实现接口方法
@Override
public void show() {
System.out.println("颜色RGB值: " + redValue + "," + greenValue + "," + blueValue);
}
}